//
//  DataGridComponent.m
//
//  Created by Chenly
//  Copyright  . All rights reserved.
//

#import "MNReportView.h"
#import <QuartzCore/QuartzCore.h>

#pragma mark - MNReportPart

typedef enum {
    MNReportPartTopLeft = 0,
    MNReportPartTopRight,
    MNReportPartBottomLeft,
    MNReportPartBottomRight
} MNReportPart;

#pragma mark - MNReportGrid 单元格

@interface MNReportGrid()

@property (nonatomic, assign) BOOL hasSetTextAlignment;  //是否设置过TextAlignment

@end

@implementation MNReportGrid

- (void)setTextAlignment:(NSTextAlignment)textAlignment
{
    _textAlignment = textAlignment;
    
    self.hasSetTextAlignment = YES;
}

@end

#pragma mark - MNReportData 数据源

@interface MNReportData()

//避免在未设置的情况下被认为设置了0，而不使用默认参数
@property(nonatomic, assign) BOOL hasSetHeaderTextAlignment;
@property(nonatomic, assign) BOOL hasSetBodyTextAlignment;
@property(nonatomic, assign) BOOL hasSetTopBorder;
@property(nonatomic, assign) BOOL hasSetBottomBorder;
@property(nonatomic, assign) BOOL hasSetLeftBorder;
@property(nonatomic, assign) BOOL hasSetRightBorder;
@property(nonatomic, assign) BOOL hasSetWidthSizeFitType;
@property(nonatomic, assign) BOOL hasSetHeightSizeFitType;

@end

@implementation MNReportData

- (void)setHeaderTextAlignment:(NSTextAlignment)headerTextAlignment
{
    self.hasSetHeaderTextAlignment = YES;
    _headerTextAlignment = headerTextAlignment;
}

- (void)setBodyTextAlignment:(NSTextAlignment)bodyTextAlignment
{
    self.hasSetBodyTextAlignment = YES;
    _bodyTextAlignment = bodyTextAlignment;
}

- (void)setWidthSizeFitType:(MNReportWidthSizeFitType)widthSizeFitType
{
    self.hasSetWidthSizeFitType = YES;
    _widthSizeFitType = widthSizeFitType;
}

- (void)setHeightSizeFitType:(MNReportHeightSizeFitType)heightSizeFitType
{
    self.hasSetHeightSizeFitType = YES;
    _heightSizeFitType = heightSizeFitType;
}

- (void)setTopBorderLineWidth:(CGFloat)topBorderLineWidth
{
    self.hasSetTopBorder = YES;
    _topBorderLineWidth = topBorderLineWidth;
}

- (void)setBottomBorderLineWidth:(CGFloat)bottomBorderLineWidth
{
    self.hasSetBottomBorder = YES;
    _bottomBorderLineWidth = bottomBorderLineWidth;
}

- (void)setLeftBorderLineWidth:(CGFloat)leftBorderLineWidth
{
    self.hasSetLeftBorder = YES;
    _leftBorderLineWidth = leftBorderLineWidth;
}

- (void)setRightBorderLineWidth:(CGFloat)rightBorderLineWidth
{
    self.hasSetRightBorder = YES;
    _rightBorderLineWidth = rightBorderLineWidth;
}

@end

#pragma mark - MNReportLabel 自定义的Label

@interface MNReportLabel()

@property (nonatomic, assign) NSInteger row;
@property (nonatomic, assign) NSInteger col;
@property (nonatomic, assign) BOOL underline;
@property (nonatomic, strong) UIImage *image;

@end

@implementation MNReportLabel

- (void)setUnderline:(BOOL)underline
{
    _underline = underline;
    [self setNeedsDisplay];
}

- (void)setImage:(UIImage *)image
{
    _image = image;
    [self setNeedsDisplay];
}

- (void)setText:(NSString *)text
{
    _image = nil;
    [super setText:text];
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect {
    
    @synchronized(self)
    {
        if (_image != nil) {
            
            [_image drawInRect:rect];
        }
        else
        {
            [super drawRect:rect];
            
            //绘制下划线
            CGContextRef ctx = UIGraphicsGetCurrentContext();
            
            if (_underline) {
                
                CGSize textSize =[self.text sizeWithFont:self.font
                                                forWidth:self.bounds.size.width
                                           lineBreakMode:self.lineBreakMode];
                
                
                NSInteger cStrCount = 0;
                
                for (int i=0; i<self.text.length; i++) {
                    unichar c = [self.text characterAtIndex:i];
                    if (c >= 0x0000 && c <= 0x00ff) {
                        cStrCount ++;
                    }
                    else
                        cStrCount += 2;
                }
                
                CGFloat fontSize = self.font.pointSize;
                CGFloat textAllLength = fontSize / 2 * cStrCount;
                
                CGFloat textRowHeight = textSize.height;
                CGFloat textRowLength = textSize.width;
                
                NSInteger textRowCount = textAllLength / textRowLength;
                if(textRowCount * textRowLength != textAllLength) textRowCount++;
                
                if ([self.textColor isEqual:[UIColor blackColor]]) {
                    //黑色时候会计算错误成绿色
                    CGContextSetRGBStrokeColor(ctx, 0, 0, 0, 1.0f);
                }
                else
                {
                    const double *colors = CGColorGetComponents(self.textColor.CGColor);
                    CGContextSetRGBStrokeColor(ctx, colors[0], colors[1], colors[2], 1.0f);
                    CGContextSetLineWidth(ctx, 0.5f);
                }
                
                CGFloat yOffset;
                CGFloat ySpace = self.frame.size.height / 2.0 - (textRowCount * textRowHeight) / 2.0;
                CGFloat length;
                
                for (int rowIndex=0; rowIndex<textRowCount; rowIndex++) {
                    
                    NSInteger subCount = 0;
                    CGFloat subLength = textRowLength * rowIndex;
                    CGFloat tempLength = 0;
                    
                    if (rowIndex != 0 && rowIndex == textRowCount - 1) {
                        
                        for (int i=0; i<self.text.length; i++) {
                            unichar c = [self.text characterAtIndex:i];
                            if (c >= 0x0000 && c <= 0x00ff) {
                                tempLength += fontSize / 2.0;
                            }
                            else
                                tempLength += fontSize;
                            
                            subCount ++;
                            
                            if (tempLength >= subLength) {
                                
                                break;
                            }
                        }
                        
                        CGSize tempTextSize =[[self.text substringFromIndex:subCount]
                                              sizeWithFont:self.font
                                              forWidth:self.bounds.size.width
                                              lineBreakMode:self.lineBreakMode];
                        length = tempTextSize.width;
                    }
                    else
                        length = textRowLength;
                    
                    yOffset = ySpace + textRowHeight * (rowIndex + 1);
                    
                    CGPoint l = CGPointMake(self.frame.size.width/2.0 - length/2.0, yOffset);
                    CGPoint r = CGPointMake(self.frame.size.width/2.0 + length/2.0, yOffset);
                    CGContextMoveToPoint(ctx, l.x, l.y);
                    CGContextAddLineToPoint(ctx, r.x, r.y);
                }
                CGContextStrokePath(ctx);
            }
        }
    }
}

@end

#pragma mark - MNReportView 报表

@interface MNReportSort()

@property (nonatomic, assign) MNReportSortType type;

@end

@implementation MNReportSort

- (instancetype)initWithSortedArray:(NSArray *)sortedArray type:(MNReportSortType)type index:(NSInteger)index
{
    _index = index;
    _type = type;
    _sortedArray = sortedArray;
    
    return self;
}

@end

@interface MNReportView()
{
    UIView *topLeftView;                //左上视图
    UIView *topRightView;               //右上视图
    UIView *bottomLeftView;             //左下视图
    UIView *bottomRightView;            //右下视图
    UIScrollView *topRightScroll;       //右上ScrollView
    UIScrollView *bottomRightScroll;    //左下ScrollView
    UIScrollView *bottomLeftScroll;     //右下ScrollView
    
    
    CGFloat headerHeight;       //表头总高度
    CGFloat bodyHeight;         //表体总高度
    CGFloat headerRowHeight;    //表头行高度
    CGFloat leftWidth;          //第一列宽度
    CGFloat gridWidth;          //数据格宽度
    CGFloat gridHeight;         //数据格高度
    
    NSInteger headerRowCount;               //表头行数
    NSMutableArray *headerRowHeightArray;   //表头行高数组
    
    NSInteger bodyRowCount;                 //表体行数
    NSMutableArray *bodyRowHeightArray;     //表体行高数组
    
    NSInteger colCount;     //总列数
    NSArray *colWidthArray; //列宽数组
    
    UIColor *headerBackgroundColor;    //表头背景色
    UIColor *bodyBackgroundColor;      //表体背景色
    
    UIColor *headerTextColor;   //表头字体颜色
    UIColor *bodyTextColor;     //表体字体颜色
    
    CGFloat headerFontSize; //表头字体大小
    CGFloat bodyFontSize;   //表体字体大小
    
    NSTextAlignment headerTextAlignment;   //表头对齐方式
    NSTextAlignment bodyTextAlignment;     //表体对齐方式
    
    UIColor *borderlineColor;  //边界线的颜色
    CGFloat horizonLineWidth;   //水平线宽度
    CGFloat verticalLineWidth;  //竖直线宽度
    
    CGFloat topBorderLineWidth;     //上边界线宽度
    CGFloat bottomBorderLineWidth;
    CGFloat leftBorderLineWidth;
    CGFloat rightBorderLineWidth;
    
    MNReportWidthSizeFitType widthSizeFitType;    //当实际表格宽度小于设地的Frame时候调整单元格宽度
    MNReportHeightSizeFitType heightSizeFitType;
    
    NSMutableDictionary *sortsDictionary;
    NSArray *yOffsetArray;
    
}

@property (nonatomic, assign) CGFloat height;
@property (nonatomic, strong) MNReportSort *currentSort;

@end

@implementation MNReportView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    
    if (self) {
        
        [self addAllSubviews];
    }
	return self;
}

- (id)initWithFrame:(CGRect)frame dataSource:(MNReportData *)dataSource
{
	self = [super initWithFrame:frame];
    
    if (self) {
        
        [self addAllSubviews];
        
        self.dataSource = dataSource;
        [self load];
    }
	return self;
}

#pragma mark - setDefaultStyle 将未进行设置的格式都设置默认风格

- (void)setDefaultStyle
{
    headerRowHeight = _dataSource.headerRowHeight == 0 ? kMNReportDefaultHeaderRowHeight : _dataSource.headerRowHeight;
    gridHeight = _dataSource.gridHeight == 0 ? kMNReportDefaultGridHeight : _dataSource.gridHeight;
    leftWidth = _dataSource.leftWidth == 0 ? kMNReportDefaultLeftWidth : _dataSource.leftWidth;
    gridWidth = _dataSource.gridWidth == 0 ? kMNReportDefaultGridWidth : _dataSource.gridWidth;
    
    if(_dataSource.headerBackgroundColor)
        headerBackgroundColor = [MNReportView colorFromHexString:_dataSource.headerBackgroundColor];
    else
        headerBackgroundColor = kMNReportDefaultHeaderBackgroundColor;
    
    if(_dataSource.bodyBackgroundColor)
        bodyBackgroundColor = [MNReportView colorFromHexString:_dataSource.bodyBackgroundColor];
    else
        bodyBackgroundColor = kMNReportDefaultBodyBackgroundColor;
    
    if(_dataSource.headerTextColor)
        headerTextColor = [MNReportView colorFromHexString:_dataSource.headerTextColor];
    else
        headerTextColor = kMNReportDefaultHeaderTextColor;
    
    if(_dataSource.bodyTextColor)
        bodyTextColor = [MNReportView colorFromHexString:_dataSource.bodyTextColor];
    else
        bodyTextColor = kMNReportDefaultBodyTextColor;
    
    if(_dataSource.headerFontSize)
        headerFontSize = _dataSource.headerFontSize;
    else
        headerFontSize = kMNReportDefaultFontSize;
    
    if(_dataSource.bodyFontSize)
        bodyFontSize = _dataSource.bodyFontSize;
    else
        bodyFontSize = kMNReportDefaultFontSize;
    
    headerTextAlignment = _dataSource.hasSetHeaderTextAlignment ? _dataSource.headerTextAlignment : kMNReportDefaultHeaderTextAlignment;
    bodyTextAlignment = _dataSource.hasSetBodyTextAlignment ?  _dataSource.bodyTextAlignment : kMNReportDefaultBodyTextAlignment;
    
    if(_dataSource.borderlineColor)
        borderlineColor = [MNReportView colorFromHexString:_dataSource.borderlineColor];
    else
        borderlineColor = kMNReportDefaultBorderlineColor;
    
    horizonLineWidth = _dataSource.horizonLineWidth == 0 ? kMNReportDefaultHorizonLineWidth : _dataSource.horizonLineWidth;
    verticalLineWidth = _dataSource.verticalLineWidth == 0 ? kMNReportDefaultVerticalLineWidth : _dataSource.verticalLineWidth;
    
    topBorderLineWidth = _dataSource.hasSetTopBorder ? _dataSource.topBorderLineWidth : 1.0;
    bottomBorderLineWidth = _dataSource.hasSetBottomBorder ? _dataSource.bottomBorderLineWidth : 1.0;
    leftBorderLineWidth = _dataSource.hasSetLeftBorder ? _dataSource.leftBorderLineWidth : 1.0;
    rightBorderLineWidth = _dataSource.hasSetRightBorder ? _dataSource.rightBorderLineWidth : 1.0;
    
    widthSizeFitType = _dataSource.hasSetWidthSizeFitType  ?  _dataSource.widthSizeFitType : MNReportWidthSizeFitTypeAll;
    heightSizeFitType = _dataSource.hasSetHeightSizeFitType ? _dataSource.heightSizeFitType : MNReportHeightSizeFitTypeNone;
}

#pragma mark - load

- (void)reload
{
    //reload重置一些参数
    self.currentSort = nil;
    colWidthArray = nil;
    sortsDictionary = nil;
    bottomRightScroll.contentOffset = CGPointMake(0, 0);
    
    [self load];
}

- (void)load
{
    //加载视图
    
    bodyRowCount = 0;
    colCount = 0;
    headerRowCount = 0;
    
    if (_dataSource.headerDatas.count != 0) {
        
        bodyRowCount = self.dataSource.bodyDatas.count;
        for (MNReportGrid *grid in _dataSource.headerDatas[0]) {
            
            colCount += grid.colspans + 1;
        }
        headerRowCount = self.dataSource.headerDatas.count;
    }
    
    [self setDefaultStyle];
    [self sizeFit];
    [self layoutAllSubviews];
    [self loadReport];
}

- (void)loadReport
{
    //计算除第一列外所需宽度
    CGFloat rightWidth = - verticalLineWidth;
    for (int colIdx=1; colIdx<colCount; colIdx++) {
        
        rightWidth += ((NSNumber *)colWidthArray[colIdx]).floatValue + verticalLineWidth;
    }
    
    //设置视图大小
    topRightScroll.frame = CGRectMake(leftBorderLineWidth + verticalLineWidth + leftWidth, topBorderLineWidth, self.frame.size.width - (leftBorderLineWidth + leftWidth + verticalLineWidth + rightBorderLineWidth), headerHeight);
    topRightScroll.contentSize = CGSizeMake(rightWidth, 0);
    
    bottomLeftScroll.frame = CGRectMake(leftBorderLineWidth, topBorderLineWidth + horizonLineWidth + headerHeight, leftWidth, self.frame.size.height - (topBorderLineWidth + headerHeight + 2 * horizonLineWidth));
    bottomLeftScroll.contentSize = CGSizeMake(0, bodyHeight);
    
    bottomRightScroll.frame = CGRectMake(leftBorderLineWidth + verticalLineWidth + leftWidth, topBorderLineWidth + horizonLineWidth + headerHeight, self.frame.size.width - (leftBorderLineWidth + leftWidth + verticalLineWidth + rightBorderLineWidth), self.frame.size.height - (topBorderLineWidth + headerHeight + 2 * horizonLineWidth));
    bottomRightScroll.contentSize = CGSizeMake(rightWidth, bodyHeight);
    
    topLeftView.frame = CGRectMake(leftBorderLineWidth, topBorderLineWidth, leftWidth, headerHeight);
    bottomLeftView.frame = CGRectMake(0, 0, leftWidth, bodyHeight);
    topRightView.frame = CGRectMake(0, 0, rightWidth, headerHeight);
    bottomRightView.frame = CGRectMake(0, 0, rightWidth, bodyHeight);
    
    //加载各个部分，给所有label添加数据和格式以及frame
    [self loadTopLeft];
    [self loadTopRight];
    [self loadBottomLeft];
    [self loadBottomRight];
    
    [self setNeedsDisplay];
    //结束本轮Runloop，立即开始刷新视图
    [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate: [NSDate date]];
    
    //所谓的边界线和分割线其实并没有画线，就是背景色在各个label的间隙中的展示。
    self.backgroundColor = borderlineColor;
}

- (void)layoutInPart:(MNReportPart)part
{
    UIView *superView;
    NSInteger countShouldAdd = 0;
    
    switch (part) {
        case MNReportPartTopLeft:
            superView = topLeftView;
            countShouldAdd = headerRowCount;
            break;
        case MNReportPartTopRight:
            superView = topRightView;
            for (NSArray *headerRow in _dataSource.headerDatas) {
                
                countShouldAdd += headerRow.count - 1;
            }
            break;
        case MNReportPartBottomLeft:
            superView = bottomLeftView;
            countShouldAdd = bodyRowCount;
            break;
        case MNReportPartBottomRight:
            superView = bottomRightView;
            countShouldAdd = bodyRowCount * (colCount - 1);
            break;
        default:
            break;
    }
    
    //视图里面label的重用
    NSInteger labelCountNeedAdd = countShouldAdd - superView.subviews.count;
    
    if (labelCountNeedAdd < 0) {
        //现有的label数量大于所需
        while (labelCountNeedAdd < 0) {
            
            MNReportLabel *l = [superView.subviews lastObject];
            [l removeFromSuperview];
            l = nil;
            labelCountNeedAdd ++;
        }
    }
    else
    {
        //现有的label数量小于所需
        while (labelCountNeedAdd > 0) {
            
            MNReportLabel *l = [[MNReportLabel alloc] init];
            [superView addSubview:l];
            labelCountNeedAdd --;
        }
    }
}

- (void)loadTopLeft
{
    CGFloat yOffset = 0;
    NSInteger index = 0;
    
    for (int rowIdx=0; rowIdx<headerRowCount; rowIdx++) {
        
        MNReportGrid *grid = _dataSource.headerDatas[rowIdx][0];
        
        CGFloat headerCellheight = ((NSNumber *)headerRowHeightArray[rowIdx]).floatValue;
        
        CGRect labelFrame = CGRectMake(0, yOffset, leftWidth, headerCellheight);
        
        MNReportLabel *l = [self labelWithFrame:labelFrame MNReportGrid:grid inPart:MNReportPartTopLeft index:index];
        l.row = 0;
        l.col = 0;
        
        index ++;
        yOffset += headerCellheight + verticalLineWidth;
    }
}

- (void)loadTopRight
{
    CGFloat yOffset = 0;
    NSInteger index = 0;
    
    for (int rowIdx=0; rowIdx<headerRowCount; rowIdx++) {
        
        CGFloat xOffset = 0;
        NSInteger colspanIndex = 0;
        
        NSArray *headerRow = _dataSource.headerDatas[rowIdx];
        
        CGFloat headerCellHeight = ((NSNumber *)headerRowHeightArray[rowIdx]).floatValue;
        
        for (int colIdx=1; colIdx<headerRow.count; colIdx++) {
            
            MNReportGrid *grid = headerRow[colIdx];
            
            CGFloat width = - verticalLineWidth;
            for (int i=0; i<grid.colspans+1; i++) {
                colspanIndex ++;
                width += ((NSNumber *)colWidthArray[colspanIndex]).floatValue + verticalLineWidth;
            }
            
            CGRect labelFrame = CGRectMake(xOffset, yOffset, width, headerCellHeight);
            
            MNReportLabel *l = [self labelWithFrame:labelFrame MNReportGrid:grid inPart:MNReportPartTopRight index:index];
            l.row = 0;
            l.col = colIdx;
            
            index ++;
            xOffset += width + verticalLineWidth;
        }
        
        yOffset += headerCellHeight + verticalLineWidth;
    }
}

- (void)loadBottomLeft
{
    //用来排序用
    NSMutableArray *tempYOffsetArray = [NSMutableArray array];
    
    CGFloat yOffset = 0;
    NSInteger index = 0;
    
    for (int rowIdx = 1; rowIdx < bodyRowCount + 1; rowIdx++) {
        
        MNReportGrid *grid = _dataSource.bodyDatas[rowIdx - 1][0];
        
        CGFloat height = ((NSNumber *)bodyRowHeightArray[rowIdx - 1]).floatValue;
        
        CGRect labelFrame = CGRectMake(0, yOffset, leftWidth, height);
        
        MNReportLabel *l = [self labelWithFrame:labelFrame MNReportGrid:grid inPart:MNReportPartBottomLeft index:index];
        l.row = rowIdx;
        l.col = 0;
        
        index ++;
        
        [tempYOffsetArray addObject:[NSNumber numberWithFloat:yOffset]];
        
        yOffset += height + horizonLineWidth;
    }
    
    yOffsetArray = tempYOffsetArray;
}

- (void)loadBottomRight
{
    CGFloat yOffset = 0;
    NSInteger index = 0;
    
    for (int rowIdx = 1; rowIdx < bodyRowCount + 1; rowIdx++) {
        
        CGFloat xOffset = 0;
        CGFloat height = ((NSNumber *)bodyRowHeightArray[rowIdx - 1]).floatValue;
        
        for (int colIdx = 1; colIdx < colCount; colIdx++) {
            
            MNReportGrid *grid = _dataSource.bodyDatas[rowIdx - 1][colIdx];
            
            CGFloat width = ((NSNumber *)colWidthArray[colIdx]).floatValue;
            
            CGRect labelFrame = CGRectMake(xOffset, yOffset, width, height);
            
            MNReportLabel *l = [self labelWithFrame:labelFrame MNReportGrid:grid inPart:MNReportPartBottomRight index:index];
            l.row = rowIdx;
            l.col = colIdx;
            
            xOffset += width + verticalLineWidth;
            index ++;
        }
        
        yOffset += height + horizonLineWidth;
    }
}

- (MNReportLabel *)labelWithFrame:(CGRect)frame MNReportGrid:(MNReportGrid *)grid inPart:(MNReportPart)part index:(NSInteger)index
{
    MNReportLabel *l;
    
    switch (part) {
        case MNReportPartTopLeft:
        case MNReportPartTopRight:
        {
            if (part == MNReportPartTopLeft) {
                
                l = topLeftView.subviews[index];
            }
            else
            {
                l = topRightView.subviews[index];
            }
            CGFloat fontSize = grid.fontSize == 0 ? headerFontSize : grid.fontSize;
            UIFont *font = grid.bold ? [UIFont boldSystemFontOfSize:fontSize] : [UIFont systemFontOfSize:fontSize];
            l.font = font;
            l.textColor = grid.textColor == nil ? headerTextColor : [MNReportView colorFromHexString:grid.textColor];
            l.backgroundColor = grid.backgroundColor == nil ? headerBackgroundColor : [MNReportView colorFromHexString:grid.backgroundColor];
            l.textAlignment = grid.hasSetTextAlignment ? grid.textAlignment : headerTextAlignment;
            break;
        }
        case MNReportPartBottomLeft:
        case MNReportPartBottomRight:
        {
            if (part == MNReportPartBottomLeft) {
                
                l = bottomLeftView.subviews[index];
            }
            else
            {
                l = bottomRightView.subviews[index];
            }
            CGFloat fontSize = grid.fontSize == 0 ? bodyFontSize : grid.fontSize;
            UIFont *font = grid.bold ? [UIFont boldSystemFontOfSize:fontSize] : [UIFont systemFontOfSize:fontSize];
            l.font = font;
            l.textColor = grid.textColor == nil ? bodyTextColor : [MNReportView colorFromHexString:grid.textColor];
            l.backgroundColor = grid.backgroundColor == nil ? bodyBackgroundColor : [MNReportView colorFromHexString:grid.backgroundColor];
            l.textAlignment = grid.hasSetTextAlignment ? grid.textAlignment : bodyTextAlignment;
            break;
        }
        default:
            break;
    }
    
    l.frame = frame;
    
    if (grid.image != nil) {
        
        l.image = grid.image;
    }
    else
    {
        l.text = grid.text;
        l.lineBreakMode = NSLineBreakByCharWrapping;
        l.numberOfLines = 0;
        l.underline = grid.underline;
    }
    
    return l;
}

#pragma mark - layout 视图布局操作

- (void)layoutAllSubviews
{
    [self layoutInPart:MNReportPartTopLeft];
    [self layoutInPart:MNReportPartTopRight];
    [self layoutInPart:MNReportPartBottomLeft];
    [self layoutInPart:MNReportPartBottomRight];
}

- (void)addAllSubviews
{
    //新建所需子视图
    topRightScroll = [[UIScrollView alloc] init];
    topRightScroll.backgroundColor = [UIColor clearColor];
    topRightScroll.scrollEnabled = NO;
    
    bottomLeftScroll = [[UIScrollView alloc] init];
    bottomLeftScroll.backgroundColor = [UIColor clearColor];
    bottomLeftScroll.scrollEnabled = NO;
    
    bottomRightScroll = [[UIScrollView alloc] init];
    bottomRightScroll.backgroundColor = [UIColor clearColor];
    bottomRightScroll.bounces = NO;
    bottomRightScroll.directionalLockEnabled = YES;
    bottomRightScroll.delegate = self;
    
    topLeftView = [[UIView alloc] init];
    topLeftView.backgroundColor = [UIColor clearColor];
    
    topRightView = [[UIView alloc] init];
    topRightView.backgroundColor = [UIColor clearColor];
    
    bottomLeftView = [[UIView alloc] init];
    bottomLeftView.backgroundColor = [UIColor clearColor];
    
    bottomRightView = [[UIView alloc] init];
    bottomRightView.backgroundColor = [UIColor clearColor];
    
    //添加各视图
    [topRightScroll addSubview:topRightView];
    [bottomLeftScroll addSubview:bottomLeftView];
    [bottomRightScroll addSubview:bottomRightView];
    
    [self addSubview:topLeftView];
    [self addSubview:topRightScroll];
    [self addSubview:bottomLeftScroll];
    [self addSubview:bottomRightScroll];
    
    //添加手势
    [self addAllGestureRecognizer];
}

- (void)addAllGestureRecognizer
{
    //添加触摸事件
    UILongPressGestureRecognizer *topLeftLongPressGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(topLeftLongPress:)];
    topLeftLongPressGR.minimumPressDuration = 1;
    [topLeftView addGestureRecognizer:topLeftLongPressGR];
    
    UILongPressGestureRecognizer *topRightLongPressGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(topRightLongPress:)];
    topRightLongPressGR.minimumPressDuration = 1;
    [topRightView addGestureRecognizer:topRightLongPressGR];
    
    UILongPressGestureRecognizer *bottomLeftlongPressGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(bottomLeftLongPress:)];
    bottomLeftlongPressGR.minimumPressDuration = 1;
    [bottomLeftView addGestureRecognizer:bottomLeftlongPressGR];
    
    UILongPressGestureRecognizer *bottomRightPressGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(bottomRightLongPress:)];
    bottomRightPressGR.minimumPressDuration = 1;
    [bottomRightView addGestureRecognizer:bottomRightPressGR];
    
    UITapGestureRecognizer *topLeftClickGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(topLeftClick:)];
    topLeftClickGR.numberOfTapsRequired = 1;
    [topLeftClickGR requireGestureRecognizerToFail:topLeftLongPressGR];
    [topLeftView addGestureRecognizer:topLeftClickGR];
    
    UITapGestureRecognizer *topRightClickGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(topRightClick:)];
    topRightClickGR.numberOfTapsRequired = 1;
    [topRightClickGR requireGestureRecognizerToFail:topRightLongPressGR];
    [topRightView addGestureRecognizer:topRightClickGR];
    
    UITapGestureRecognizer *bottomLeftClickGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(bottomLeftClick:)];
    bottomLeftClickGR.numberOfTapsRequired = 1;
    [bottomLeftClickGR requireGestureRecognizerToFail:bottomLeftlongPressGR];
    [bottomLeftView addGestureRecognizer:bottomLeftClickGR];
    
    UITapGestureRecognizer *bottomRightClickGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(bottomRightClick:)];
    bottomRightClickGR.numberOfTapsRequired = 1;
    [bottomRightClickGR requireGestureRecognizerToFail:bottomRightPressGR];
    [bottomRightView addGestureRecognizer:bottomRightClickGR];
}

#pragma mark - size to fit 报表大小自适应调整

- (void)sizeFit
{
    //报表宽度的设置
    CGFloat reportWidth = 0;
    if (_dataSource.colWidthArray.count > 0) {
        
        //有配置每一列的列宽
        colWidthArray = _dataSource.colWidthArray;
        
        leftWidth = ((NSNumber *)colWidthArray[0]).floatValue;
        
        for (NSNumber *number in colWidthArray) {
            
            reportWidth += number.floatValue + horizonLineWidth;
        }
        reportWidth = reportWidth - horizonLineWidth + leftBorderLineWidth + rightBorderLineWidth;
    }
    else
    {
        //未配置每一列的列宽
        reportWidth = leftWidth + (gridWidth + horizonLineWidth) * (colCount - 1) + leftBorderLineWidth + rightBorderLineWidth;
    }
    
    //表头行高的设置
    headerHeight = headerRowHeight * headerRowCount + verticalLineWidth * (headerRowCount - 1);
    
    if (_dataSource.autoFitHeaderHeight)  {
        
        headerRowHeightArray = [[NSMutableArray alloc] init];
        
        for (NSArray *row in _dataSource.headerDatas) {
            
            CGFloat maxHeight = headerRowHeight;
            NSInteger colspanIndex = 0;
            
            for (int colIdx=0; colIdx<row.count; colIdx++) {
                
                MNReportGrid *grid = row[colIdx];
                
                CGFloat width = - verticalLineWidth;
                for (int i=0; i < grid.colspans + 1; i++) {

                    if (colWidthArray.count != 0) {
                        width += ((NSNumber *)colWidthArray[colspanIndex]).floatValue + verticalLineWidth;
                        colspanIndex ++;
                    }
                    else
                        width += gridWidth + verticalLineWidth;
                }
                
                CGFloat fontSize = grid.fontSize == 0 ? headerFontSize : grid.fontSize;
                UIFont *font = grid.bold ? [UIFont boldSystemFontOfSize:fontSize] : [UIFont systemFontOfSize:fontSize];
                
                CGSize textSize = [grid.text sizeWithFont:font constrainedToSize:CGSizeMake(width, MAXFLOAT) lineBreakMode:NSLineBreakByCharWrapping];
                
                NSInteger textRowCount = (NSInteger)(textSize.height / fontSize);
                CGFloat currentHeight = textRowCount * (fontSize + 3);
                
                maxHeight = currentHeight > maxHeight ? currentHeight : maxHeight;
            }
            
            [headerRowHeightArray addObject:[NSNumber numberWithFloat:maxHeight]];
            
            headerHeight += maxHeight - headerRowHeight;
        }
    }
    
    //表体高度的设置
    bodyHeight = gridHeight * bodyRowCount + verticalLineWidth * (bodyRowCount - 1);
    
    if (_dataSource.autoFitBodyHeight) {
        
        bodyRowHeightArray = [[NSMutableArray alloc] init];
        
        for (NSArray *row in _dataSource.bodyDatas) {
            
            CGFloat maxHeight = gridHeight;
            
            for (int colIdx=0; colIdx<row.count; colIdx++) {
                
                MNReportGrid *grid = row[colIdx];
                
                CGFloat width;
                if (colWidthArray != nil) {
                    
                    width = ((NSNumber *)colWidthArray[colIdx]).floatValue;
                }
                else
                    width = gridWidth;
                
                CGFloat currentHeight = 0;
                
                CGFloat fontSize = grid.fontSize == 0 ? bodyFontSize : grid.fontSize;
                UIFont *font = grid.bold ? [UIFont boldSystemFontOfSize:fontSize] : [UIFont systemFontOfSize:fontSize];

                CGSize textSize = [grid.text sizeWithFont:font constrainedToSize:CGSizeMake(width, MAXFLOAT) lineBreakMode:NSLineBreakByCharWrapping];
                
                currentHeight = (int)(textSize.height / fontSize) * (fontSize + 3);
                
                maxHeight = currentHeight > maxHeight ? currentHeight : maxHeight;
            }
            
            [bodyRowHeightArray addObject:[NSNumber numberWithFloat:maxHeight]];
            
            bodyHeight += maxHeight - gridHeight;
        }
    }
    
    //表frame的自适应
    CGFloat reportHeight = topBorderLineWidth + headerHeight + verticalLineWidth + bodyHeight + bottomBorderLineWidth;
    
    CGFloat frameWidth = self.frame.size.width;
    CGFloat frameHeight = self.frame.size.height;
    
    _height = reportHeight;
    
    if (frameHeight == 0) {
        //当表格的frame.size.height设为0则表格自动将行高设为实际行高(全部展示不用滑动)
        self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, frameWidth, reportHeight);
    }
    
    if (reportWidth < frameWidth) {
        
        if (colWidthArray != nil) {
            
            widthSizeFitType = MNReportWidthSizeFitTypeNone;
        }
        
        switch (widthSizeFitType) {
            case MNReportWidthSizeFitTypeNone:
                self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, reportWidth, self.frame.size.height);
                break;
            case MNReportWidthSizeFitTypeAll:
                gridWidth = (frameWidth - ((colCount - 1) * verticalLineWidth + leftBorderLineWidth + rightBorderLineWidth)) / (float)colCount;
                leftWidth = gridWidth;
                break;
            case MNReportWidthSizeFitTypeWithoutLeft:
                gridWidth = (frameWidth - ((colCount - 1) * verticalLineWidth + leftBorderLineWidth + rightBorderLineWidth) - leftWidth) / ((float)colCount - 1);
                break;
            default:
                break;
        }
    }
    
    if (reportHeight < frameHeight) {
        //当实际表的高度(根据数据和配置的行高计算得出)小于设定的frame的高度的时候，进行自适应(按照实际大小布局、将整体拉伸、表头不拉伸表体拉伸)。
        if (_dataSource.autoFitBodyHeight && heightSizeFitType == MNReportHeightSizeFitTypeAll) {
            //当表头自适应行高时候不拉伸表头
            heightSizeFitType = MNReportHeightSizeFitTypeWithoutHeader;
        }
        if (_dataSource.autoFitBodyHeight) {
            //当表体自适应行高时候全部不拉伸
            heightSizeFitType = MNReportHeightSizeFitTypeNone;
        }
        
        switch (heightSizeFitType) {
            case MNReportHeightSizeFitTypeNone:
                self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, reportHeight);
                break;
            case MNReportHeightSizeFitTypeAll:
                gridHeight = (frameHeight - (bodyRowCount * horizonLineWidth + topBorderLineWidth + bottomBorderLineWidth)) / (float)(bodyRowCount + headerRowCount);
                bodyHeight = gridHeight * bodyRowCount + verticalLineWidth * (bodyRowCount - 1);
                headerRowHeight = gridHeight;
                headerHeight = headerRowHeight * headerRowCount + verticalLineWidth * (headerRowCount - 1);
                break;
            case MNReportHeightSizeFitTypeWithoutHeader:
                gridHeight = (frameHeight - (bodyRowCount * horizonLineWidth + topBorderLineWidth + bottomBorderLineWidth) - headerHeight) / (float)bodyRowCount;
                bodyHeight = gridHeight * bodyRowCount + verticalLineWidth * (bodyRowCount - 1);
                break;
            default:
                break;
        }
        
    }
    
    if (colWidthArray == nil) {
        
        NSMutableArray *array = [[NSMutableArray alloc] init];
        
        [array addObject:[NSNumber numberWithFloat:leftWidth]];
        for (int colIdex = 1; colIdex < colCount; colIdex++) {
            
            [array addObject:[NSNumber numberWithFloat:gridWidth]];
        }
        colWidthArray = array;
    }
    
    if (!_dataSource.autoFitHeaderHeight)  {
        
        headerRowHeightArray = [[NSMutableArray alloc] init];
        
        for (int i = 0; i < _dataSource.headerDatas.count; i ++) {
            
            [headerRowHeightArray addObject:[NSNumber numberWithFloat:headerRowHeight]];
        }
    }
    
    if (!_dataSource.autoFitBodyHeight) {
        
        bodyRowHeightArray = [[NSMutableArray alloc] init];
        
        for (int i = 0; i < _dataSource.bodyDatas.count; i++) {
            
            [bodyRowHeightArray addObject:[NSNumber numberWithFloat:gridHeight]];
        }
    }
}

#pragma mark - height 通过datasource获取生成报表高度

//用于tableView中展示报表时计算cell高度所需

+ (CGFloat)heightForData:(MNReportData *)data;
{
    static MNReportView *instanceForHeight;
    
    if (instanceForHeight == nil) {
        
        instanceForHeight = [MNReportView alloc];
    }
    instanceForHeight.dataSource = data;
    
    return instanceForHeight.height;
}

- (CGFloat)height
{
    _height = 0;
    
    bodyRowCount = 0;
    colCount = 0;
    headerRowCount = 0;
    
    if (_dataSource.headerDatas != nil || _dataSource.headerDatas.count != 0) {
        
        bodyRowCount = self.dataSource.bodyDatas.count;
        for (MNReportGrid *grid in _dataSource.headerDatas[0]) {
            
            colCount += grid.colspans + 1;
        }
        headerRowCount = self.dataSource.headerDatas.count;
    }
    
    [self setDefaultStyle];
    [self sizeFit];
    
    return _height;
}

#pragma mark - sort 排序

- (void)setCurrentSort:(MNReportSort *)currentSort
{
    if (currentSort) {
        
        _currentSort = [[MNReportSort alloc] initWithSortedArray:currentSort.sortedArray type:currentSort.type index:currentSort.index];
    }
}

- (void)sortAtIndex:(NSInteger)index
{
    MNReportSort *sort = [sortsDictionary valueForKey:[NSString stringWithFormat:@"%ld", index]];

    if (sort) {
        
        if (self.currentSort) {
            //去掉旧排序列表头的箭头
            for (MNReportLabel *label in topRightView.subviews) {
                
                if (label.col == self.currentSort.index) {
                    
                    label.text = [label.text substringToIndex:label.text.length - 1];
                    break;
                }
            }
        }
        
        if (sort.index == self.currentSort.index) {
            
            self.currentSort.type = - self.currentSort.type;
        }
        else
        {
            self.currentSort = sort;
        }
        [self doSort];
    }
}

- (void)addSort:(MNReportSort *)sort
{
    if (!sortsDictionary) {
        
        sortsDictionary = [[NSMutableDictionary alloc] init];
    }
    [sortsDictionary setValue:sort forKey:[NSString stringWithFormat:@"%ld", sort.index]];
}

- (void)doSort
{
    NSInteger sortIndex = 0;
    NSInteger rowIndex = 0;
    
    if (self.currentSort.type == MNReportSortTypeDSC) {
        
        sortIndex = bodyRowCount - 1;
    }
    
    //被排序列表头添加箭头
    for (MNReportLabel *label in topRightView.subviews) {
        
        if (label.col == self.currentSort.index) {
            
            if (self.currentSort.type == MNReportSortTypeDSC)
            {
                label.text = [label.text stringByAppendingString:@"↓"];
            }
            else
            {
                label.text = [label.text stringByAppendingString:@"↑"];
            }
            break;
        }
    }
    
    while (rowIndex < bodyRowCount) {
        
        float yOffset = [yOffsetArray[rowIndex] floatValue];
        int rowIdx = [self.currentSort.sortedArray[sortIndex] intValue];
        
        for (MNReportLabel *label in bottomRightView.subviews) {
            
            if (label.row == rowIdx) {
                
                label.frame = CGRectMake(label.frame.origin.x, yOffset, label.frame.size.width, label.frame.size.height);
            }
        }
        for (MNReportLabel *label in bottomLeftView.subviews) {
            
            if (label.row == rowIdx) {
                
                label.frame = CGRectMake(label.frame.origin.x, yOffset, label.frame.size.width, label.frame.size.height);
            }
        }
        
        sortIndex -= self.currentSort.type;
        rowIndex ++;
    }
}

#pragma mark - hexString to UIColor

+ (UIColor *)colorFromHexString:(NSString *)hexString
{
    NSString *cString = [[hexString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
    
    if ([cString length] < 6) return [UIColor blackColor];
    if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2];
    if ([cString hasPrefix:@"#"]) cString = [cString substringFromIndex:3];
    if ([cString length] != 6) return [UIColor blackColor];
    
    NSRange range;
    range.location = 0;
    range.length = 2;
    NSString *rString = [cString substringWithRange:range];
    range.location = 2;
    NSString *gString = [cString substringWithRange:range];
    range.location = 4;
    NSString *bString = [cString substringWithRange:range];
    unsigned int r, g, b;
    
    [[NSScanner scannerWithString:rString] scanHexInt:&r];
    [[NSScanner scannerWithString:gString] scanHexInt:&g];
    [[NSScanner scannerWithString:bString] scanHexInt:&b];
    
    return [UIColor colorWithRed:((float) r / 255.0f)
                           green:((float) g / 255.0f)
                            blue:((float) b / 255.0f)
                           alpha:1.0f];
}


#pragma mark - scrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (scrollView == bottomRightScroll) {
        topRightScroll.contentOffset = CGPointMake(bottomRightScroll.contentOffset.x, 0);
        bottomLeftScroll.contentOffset = CGPointMake(0, bottomRightScroll.contentOffset.y);
    }
}

#pragma mark - handle touch 触摸事件相关

//获取被点击的Label
- (MNReportLabel *)getTouchLabel:(UIGestureRecognizer *)sender inPart:(MNReportPart)part
{
    UIView *inView;
    
    switch (part) {
        case MNReportPartTopLeft:
            inView = topLeftView;
            break;
        case MNReportPartTopRight:
            inView = topRightView;
            break;
        case MNReportPartBottomLeft:
            inView = bottomLeftView;
            break;
        case MNReportPartBottomRight:
            inView = bottomRightView;
            break;
        default:
            break;
    }
    
    CGPoint point = [sender locationInView:inView];
    
    for (MNReportLabel *label in inView.subviews) {
        
        if(CGRectContainsPoint(label.frame, point))
        {
            return label;
        }
    }
    return nil;
}

- (void)topLeftClick:(UITapGestureRecognizer*)sender
{
    if ([_delegate respondsToSelector:@selector(MNReportView:clickInLabel:)]) {
        MNReportLabel *label = [self getTouchLabel:sender inPart:MNReportPartTopLeft];
        [_delegate MNReportView:self clickInLabel:label];
    }
}

- (void)topRightClick:(UITapGestureRecognizer*)sender
{
    if ([_delegate respondsToSelector:@selector(MNReportView:clickInLabel:)]) {
        MNReportLabel *label = [self getTouchLabel:sender inPart:MNReportPartTopRight];
        [_delegate MNReportView:self clickInLabel:label];
    }
}

- (void)bottomLeftClick:(UITapGestureRecognizer*)sender
{
    if ([_delegate respondsToSelector:@selector(MNReportView:clickInLabel:)]) {
        MNReportLabel *label = [self getTouchLabel:sender inPart:MNReportPartBottomLeft];
        [_delegate MNReportView:self clickInLabel:label];
    }
}

- (void)bottomRightClick:(UITapGestureRecognizer*)sender
{
    if ([_delegate respondsToSelector:@selector(MNReportView:clickInLabel:)]) {
        MNReportLabel *label = [self getTouchLabel:sender inPart:MNReportPartBottomRight];
        [_delegate MNReportView:self clickInLabel:label];
    }
}

- (void)topLeftLongPress:(UILongPressGestureRecognizer*)sender
{
    if (sender.state == UIGestureRecognizerStateBegan && [_delegate respondsToSelector:@selector(MNReportView:longPressInLabel:)]) {
        MNReportLabel *label = [self getTouchLabel:sender inPart:MNReportPartTopLeft];
        [_delegate MNReportView:self longPressInLabel:label];
    }
}

- (void)topRightLongPress:(UILongPressGestureRecognizer*)sender
{
    if (sender.state == UIGestureRecognizerStateBegan && [_delegate respondsToSelector:@selector(MNReportView:longPressInLabel:)]) {
        MNReportLabel *label = [self getTouchLabel:sender inPart:MNReportPartTopRight];
        [_delegate MNReportView:self longPressInLabel:label];
    }
}

- (void)bottomLeftLongPress:(UILongPressGestureRecognizer*)sender
{
    if (sender.state == UIGestureRecognizerStateBegan && [_delegate respondsToSelector:@selector(MNReportView:longPressInLabel:)]) {
        MNReportLabel *label = [self getTouchLabel:sender inPart:MNReportPartBottomLeft];
        [_delegate MNReportView:self longPressInLabel:label];
    }
}

- (void)bottomRightLongPress:(UILongPressGestureRecognizer*)sender
{
    if (sender.state == UIGestureRecognizerStateBegan && [_delegate respondsToSelector:@selector(MNReportView:longPressInLabel:)]) {
        MNReportLabel *label = [self getTouchLabel:sender inPart:MNReportPartBottomRight];
        [_delegate MNReportView:self longPressInLabel:label];
    }
}

@end

